package com.rad.net.protocol.android.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import com.rad.net.protocol.android.encoder.FieldInfo;
import com.rad.net.protocol.common.annotation.Transient;

/**
 * 类说明： 反射解析对象工具类
 * 
 * @author xinhui.cheng
 * @date 2014-8-20
 * @version 1.0
 */
public class ClassHelper {

	private static final String TAG = ClassHelper.class.getSimpleName();

	private ClassHelper() {
	}

	/**
	 * 加载一个类的所有成员变量，去除使用{@link Transient}、static、transient修饰的变量以及需要过滤的字段。
	 * 外部通过调用此方法对<b>cmd</b>进行处理
	 * @param clazz cmd的class对象
	 * @param filterFieldNames
	 *            需要过滤的字段名
	 * @return 属性值域对象链表
	 */
	public static ArrayList<FieldInfo> loadClassFields(Class<?> clazz,
			Set<String> filterFieldNames) {
		if (clazz == null) {
			return null;
		}
		if (filterFieldNames == null) {
			filterFieldNames = new HashSet<String>();
		}
		ArrayList<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>();
		ArrayList<Field> fieldList = new ArrayList<Field>();
		fetchFields(fieldList, clazz);
		for (Field f : fieldList) {
			int modifiers = f.getModifiers();
			Transient ignore = f.getAnnotation(Transient.class);
			if (ignore == null && !Modifier.isStatic(modifiers)
					&& !Modifier.isTransient(modifiers)) {
				if (!filterFieldNames.contains(f.getName())) {
					FieldInfo fi = buildFieldInfo(clazz, f);
					fieldInfoList.add(fi);
				}
			} else {
				LogUtils.i(TAG, "Ignore field: " + clazz.getSimpleName()
						+ "." + f.getName());
			}
		}

		return fieldInfoList;
	}

	/**
	 * 获取目标类和其所有父类的所有字段
	 * @param fields 储存字段的容器
	 * @param clazz 目标类
	 */
	private static void fetchFields(List<Field> fields, Class<?> clazz) {
		Field[] fs = clazz.getDeclaredFields();
		for (Field f : fs) {
			fields.add(f);
		}

		Class<?> su = clazz.getSuperclass();
		if (su != null) {
			fetchFields(fields, su);
		}
	}

	/**
	 * 根据一个字段对象生成一个属性值域对象
	 * @param clazz cmd的class对象
	 * @param f 字段对象
	 * @return 属性值域对象
	 */
	public static FieldInfo buildFieldInfo(Class<?> clazz, Field f) {
		FieldInfo fInfo = new FieldInfo();
		fInfo.setField(f);
		String fn = f.getName();
		String m = fn.substring(0, 1).toUpperCase(Locale.US);
		if (fn.length() > 1) {
			m += fn.substring(1);
		}
		String get = "get" + m;
		String set = "set" + m;
		if (f.getType() == Boolean.class || f.getType() == boolean.class) {
			get = "is" + m;
		}
		fInfo.setGetMethod(getMethod(clazz, get));
		fInfo.setSetMethod(getMethod(clazz, set, f.getType()));
		return fInfo;
	}

	private static Method getMethod(Class<?> clazz, String name,
			Class<?>... parameterTypes) {
		try {
			return clazz.getMethod(name, parameterTypes);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return null;
		}
	}

}
